# 导入mnist数据
from tensorflow.examples.tutorials.mnist import input_data

import tensorflow as tf

mnist = input_data.read_data_sets('MNIST_data', one_hot=True)

# TensorFlow程序的常见用法是首先创建一个图形，然后在会话中启动它。
# 在这里，我们使用便利的InteractiveSession类，
# 这使得TensorFlow更加灵活地了解如何构建代码。
# 它允许您将构建计算图的操作 与运行图的操作交错 。
# 在IPython等交互式环境中工作时，这特别方便。
# 如果你不使用一个 InteractiveSession，
# 那么你应该在开始会话和启动图之前建立整个计算 图。

sess = tf.InteractiveSession()

# 我们通过为输入图像和目标输出类创建节点来开始构建计算图
x = tf.placeholder(tf.float32, shape=[None, 784])
y_ = tf.placeholder(tf.float32, shape=[None, 10])

# 它们都是placeholder ，TensorFlow运行计算时输入的值。

# 输入图像x将由浮点数的二维张量组成。
# 在这里，我们分配给它一个shape的[None, 784]，
# 在那里784是单个的维数由28像素MNIST图像扁平28，以及None指示所述第一尺寸，
# 对应于批量大小，可以是任何大小的。目标输出类y_也将由二维张量组成，
# 其中每行是一个单热的10维向量，指示对应的MNIST图像属于哪个数字类别（0到9）。

# 现在定义我们模型的权重W和偏差b
W = tf.Variable(tf.zeros([784, 10]))
b = tf.Variable(tf.zeros([10]))

# Variable是生活在TensorFlow的计算图中的一个值。
# 它可以被使用，甚至被计算修改。
# 在机器学习应用中，人们通常将模型参数设为 Variables。

# 我们将呼叫中每个参数的初始值传递给tf.Variable。
# 在这种情况下，我们初始化为零W和b张量充满零。
# W是一个784x10矩阵（因为我们有784个输入特征和10个输出），
# b是一个10维向量（因为我们有10个类）。

# 在Variable会话中可以使用s 之前，必须使用该会话对其进行初始化。
# 这一步取已经指定的初始值（在这种情况下，张量满了零），
# 并将它们分配给每一个 Variable。这可以Variables一次完成：
sess.run(tf.global_variables_initializer())

# 我们现在可以实现我们的回归模型。
# 只需要一行！我们将矢量化的输入图像乘以x权重矩阵W，加上偏差b。
y = tf.matmul(x, W) + b

# 我们可以很容易地指定一个损失函数。
# 损失表明模型的预测在一个例子上有多糟糕; 我们尽量减少，而在所有的例子训练。
# 在这里，我们的损失函数是目标和应用于模型预测的softmax激活函数之间的交叉熵。
cross_entropy = tf.reduce_mean(
    tf.nn.softmax_cross_entropy_with_logits(labels=y_, logits=y))

# 请注意，
# tf.nn.softmax_cross_entropy_with_logits
# 在模型的非标准化模型预测中内部应用softmax，并在所有类别上求和，
# 并tf.reduce_mean取这些和的平均值。

# 现在我们已经定义了我们的模型和训练损失函数，使用TensorFlow进行训练是很简单的。
# 由于TensorFlow知道整个计算图，
# 因此可以使用自动微分来查找关于每个变量的损失的梯度。
# TensorFlow有多种 内置的优化算法。
# 对于这个例子，我们将使用最陡的梯度下降，步长为0.5，下降交叉熵。

train_step = tf.train.GradientDescentOptimizer(0.5).minimize(cross_entropy)

# TensorFlow在这一行中实际上做了什么是在计算图中添加新的操作。
# 这些操作包括计算梯度，计算参数更新步骤以及将更新步骤应用于参数。

# 运行train_step时返回的操作将对参数应用渐变下降更新。
# 训练模型可以通过反复运行来完成train_step。
for _ in range(1000):
    batch = mnist.train.next_batch(100)
    train_step.run(feed_dict={x: batch[0], y_: batch[1]})

# 我们在每次训练迭代中加载100个训练样例。
# 然后我们运行这个 train_step操作，
# feed_dict用来替换placeholder张量 x和y_训练样例。
# 请注意，你可以用你的计算图中的任何张量代替feed_dict- 它不仅限于 placeholders

# 首先我们要弄清楚我们在哪里预测了正确的标签。
# tf.argmax是一个非常有用的函数，它可以使您沿某个轴在张量中输入最高的索引。
# 例如，tf.argmax(y,1)我们的模型认为是每个输入最有可能的标签，
# tf.argmax(y_,1)而是真正的标签。
# 我们可以tf.equal用来检查我们的预测是否符合事实。

correct_prediction = tf.equal(tf.argmax(y, 1), tf.argmax(y_, 1))

# 这给了我们一个布尔的列表。为了确定什么分数是正确的，
# 我们转换为浮点数，然后取平均值。
# 例如， [True, False, True, True]会变成[1,0,1,1]哪个会变成0.75。

accuracy = tf.reduce_mean(tf.cast(correct_prediction, tf.float32))

# 最后，我们可以评估我们的测试数据的准确性。
print(accuracy.eval(feed_dict={x: mnist.test.images, y_: mnist.test.labels}))
